﻿using System;
using System.ComponentModel;
using System.Data;
using MySql.Data.MySqlClient;
using System.Drawing;
using System.Windows.Forms;

namespace Demo
{
    public partial class DataAdd : Form
    {
        private int? entryId;
        private char fType;
        private string? currentFilePath;

        private bool isDragging;
        private Point dragOffset;

        private const int MonthsPerYear = 12;
        private const int MaxMonthsForTypeA = 3 * MonthsPerYear;

        public DataAdd()
        {
            InitializeComponent();
            entryId = null;
            fType = 'A';
            currentFilePath = null;

            WireRuntimeEvents();

            if (!IsDesignMode())
            {
                TraditionalChineseHelper.Apply(this);
                AttachDragHandler(groupControl1);
                AttachDragHandler(groupControl2);
                AttachDragHandler(groupControl3);
                AttachDragHandler(groupControl4);
                AttachDragHandler(groupControl5);
                AttachDragHandler(groupControl6);
                AttachDragHandler(groupControl8);
            }
        }

        public DataAdd(char fType, int? entryId = null) : this()
        {
            this.fType = fType;
            this.entryId = entryId;
        }

        private void WireRuntimeEvents()
        {
            toolStripButton2.Click += (_, __) =>
            {
                DialogResult = DialogResult.Cancel;
                Close();
            };
        }

        private void FrmTZ_Scan_Add_Load(object sender, EventArgs e)
        {
            InitializeDefaults();

            chkEnableReportPassword.CheckedChanged += (_, __) => UpdatePasswordInputState();
            UpdatePasswordInputState();

            if (entryId.HasValue)
            {
                Text = "编辑测试资料";
                LoadEntry(entryId.Value);
            }
            else
            {
                Text = "新增测试资料";
            }
        }

        private void InitializeDefaults()
        {
            dtpTestDate.Value = DateTime.Today;
            dtpBirthDate.Value = DateTime.Today;
            cmbGrade.SelectedIndex = -1;
            cmbParentEducation.SelectedIndex = -1;
        }

        private void UpdatePasswordInputState()
        {
            txtPasswordInput.Enabled = chkEnableReportPassword.Checked;
            if (!txtPasswordInput.Enabled)
            {
                txtPasswordInput.Clear();
            }
        }

        private void LoadEntry(int id)
        {
            try
            {
                using var connection = new MySqlConnection(DatabaseConfig.ConnectionString);
                using var command = new MySqlCommand(@"
SELECT ParameterNumber,
       MainTesterName,
       ChildName,
       TestDate,
       BirthDate,
       Grade,
       ParentEducation,
       PhoneNumber,
       VideoGame,
       Address,
       Remarks,
       ChildGender,
       HandPreference,
       Blocks,
       Comprehension,
       MatrixReasoning,
       BugSearch,
       PictureMemory,
       Similarities,
       PictureConcepts,
       Cancellation,
       AnimalHome,
       Puzzle,
       AnimalCoding,
       Understanding,
       PictureRecognition,
       PictureNaming,
       RandomCancellation,
       OrderedCancellation,
       ConfidenceLevel,
       StatisticalSignificance,
       ComparisonBasis,
       CalculationMethod,
       CalculationMethod2,
       FilePath,
       ReportPassword,
       FType
FROM TestEntries
WHERE EntryID = @EntryID;", connection);
                command.Parameters.AddWithValue("@EntryID", id);

                connection.Open();
                MySqlCollationHelper.EnsureGeneralCollation(connection);
                using var reader = command.ExecuteReader();
                if (!reader.Read())
                {
                    DevExpress.XtraEditors.XtraMessageBox.Show(
                        TraditionalChineseHelper.Convert("未找到對應的資料記錄。"),
                        TraditionalChineseHelper.Convert("提示"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information);
                    DialogResult = DialogResult.Cancel;
                    Close();
                    return;
                }

                entryId = id;

                var dbFType = reader["FType"]?.ToString();
                if (!string.IsNullOrWhiteSpace(dbFType))
                {
                    fType = dbFType![0];
                }

                txtParameterCode.Text = reader["ParameterNumber"]?.ToString();
                txtTesterName.Text = reader["MainTesterName"]?.ToString();
                txtChildName.Text = reader["ChildName"]?.ToString();

                if (reader["TestDate"] != DBNull.Value)
                {
                    dtpTestDate.Value = Convert.ToDateTime(reader["TestDate"]);
                }

                if (reader["BirthDate"] != DBNull.Value)
                {
                    dtpBirthDate.Value = Convert.ToDateTime(reader["BirthDate"]);
                }

                ApplyComboSelection(cmbGrade, reader["Grade"]?.ToString());
                ApplyComboSelection(cmbParentEducation, reader["ParentEducation"]?.ToString());

                txtPhoneNumber.Text = reader["PhoneNumber"]?.ToString();
                txtVideoGames.Text = reader["VideoGame"]?.ToString();
                txtContactAddress.Text = reader["Address"]?.ToString();
                memoParentRemark.Text = reader["Remarks"]?.ToString();

                SetGender(reader["ChildGender"]?.ToString());
                SetHandPreference(reader["HandPreference"]?.ToString());

                numBlock.Value = GetNumeric(reader["Blocks"], numBlock);
                numInformation.Value = GetNumeric(reader["Comprehension"], numInformation);
                numMatrix.Value = GetNumeric(reader["MatrixReasoning"], numMatrix);
                numBugSearch.Value = GetNumeric(reader["BugSearch"], numBugSearch);
                numPictureMemory.Value = GetNumeric(reader["PictureMemory"], numPictureMemory);
                numSimilarities.Value = GetNumeric(reader["Similarities"], numSimilarities);
                numConcepts.Value = GetNumeric(reader["PictureConcepts"], numConcepts);
                numCancellation.Value = GetNumeric(reader["Cancellation"], numCancellation);
                numAnimalHome.Value = GetNumeric(reader["AnimalHome"], numAnimalHome);
                numPuzzle.Value = GetNumeric(reader["Puzzle"], numPuzzle);
                numAnimalCoding.Value = GetNumeric(reader["AnimalCoding"], numAnimalCoding);
                numComprehension.Value = GetNumeric(reader["Understanding"], numComprehension);
                numPictureRecognition.Value = GetNumeric(reader["PictureRecognition"], numPictureRecognition);
                numPictureNaming.Value = GetNumeric(reader["PictureNaming"], numPictureNaming);
                numRandomCancellation.Value = GetNumeric(reader["RandomCancellation"], numRandomCancellation);
                numOrderedCancellation.Value = GetNumeric(reader["OrderedCancellation"], numOrderedCancellation);

                SetReliability(reader["ConfidenceLevel"]?.ToString());
                SetSignificance(reader["StatisticalSignificance"]?.ToString());
                SetComparisonBasis(reader["ComparisonBasis"]?.ToString());
                SetCalculationMethod(reader["CalculationMethod"]?.ToString());
                SetAlternativeMethod(reader["CalculationMethod2"]?.ToString());

                currentFilePath = reader["FilePath"]?.ToString();
                var encryptedPassword = reader["ReportPassword"]?.ToString();
                if (!string.IsNullOrWhiteSpace(encryptedPassword))
                {
                    chkEnableReportPassword.Checked = true;
                    txtPasswordInput.Text = ReportPasswordProtector.Decrypt(encryptedPassword!);
                }
                else
                {
                    chkEnableReportPassword.Checked = false;
                    txtPasswordInput.Clear();
                }
            }
            catch (Exception ex)
            {
                DevExpress.XtraEditors.XtraMessageBox.Show(
                    TraditionalChineseHelper.Convert($"載入資料失敗：{ex.Message}"),
                    TraditionalChineseHelper.Convert("錯誤"),
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private static void ApplyComboSelection(System.Windows.Forms.ComboBox comboBox, string? value)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                comboBox.SelectedIndex = -1;
                return;
            }

            var index = comboBox.Items.IndexOf(value);
            comboBox.SelectedIndex = index;
        }

        private void SetGender(string? value)
        {
            if (string.Equals(value, "女性", StringComparison.OrdinalIgnoreCase))
            {
                radioGenderFemale.Checked = true;
            }
            else
            {
                radioGenderMale.Checked = true;
            }
        }

        private void SetHandPreference(string? value)
        {
            if (string.Equals(value, "左手", StringComparison.OrdinalIgnoreCase))
            {
                radioHandLeft.Checked = true;
            }
            else if (string.Equals(value, "不确定", StringComparison.OrdinalIgnoreCase))
            {
                radioHandUnknown.Checked = true;
            }
            else
            {
                radioHandRight.Checked = true;
            }
        }

        private void SetReliability(string? value)
        {
            if (string.Equals(value, "90%", StringComparison.OrdinalIgnoreCase))
            {
                radioReliability90.Checked = true;
            }
            else
            {
                radioReliability95.Checked = true;
            }
        }

        private void SetSignificance(string? value)
        {
            switch (value)
            {
                case "0.05":
                    radioSignificance005.Checked = true;
                    break;
                case "0.10":
                    radioSignificance010.Checked = true;
                    break;
                case "0.15":
                    radioSignificance015.Checked = true;
                    break;
                default:
                    radioSignificance001.Checked = true;
                    break;
            }
        }

        private void SetComparisonBasis(string? value)
        {
            radioComparisonOverall.Checked = true;
        }

        private void SetCalculationMethod(string? value)
        {
            if (string.Equals(value, "比例估算法", StringComparison.OrdinalIgnoreCase))
            {
                radioMethodProportion.Checked = true;
            }
            else
            {
                radioMethodReplacement.Checked = true;
            }
        }

        private void SetAlternativeMethod(string? value)
        {
            if (string.Equals(value, "比例估算法", StringComparison.OrdinalIgnoreCase))
            {
                radioAlternativeProportion.Checked = true;
            }
            else
            {
                radioAlternativeReplacement.Checked = true;
            }
        }

        private static decimal GetNumeric(object value, NumericUpDown control)
        {
            if (value == DBNull.Value)
            {
                return control.Minimum;
            }

            var decimalValue = Convert.ToDecimal(value);
            if (decimalValue < control.Minimum)
            {
                return control.Minimum;
            }

            if (decimalValue > control.Maximum)
            {
                return control.Maximum;
            }

            return decimalValue;
        }

        private bool ValidateInputs()
        {
            if (string.IsNullOrWhiteSpace(txtParameterCode.Text))
            {
                ShowValidation("請輸入參數編號。", txtParameterCode);
                return false;
            }

            if (string.IsNullOrWhiteSpace(txtTesterName.Text))
            {
                ShowValidation("請輸入主試名字。", txtTesterName);
                return false;
            }

            if (string.IsNullOrWhiteSpace(txtChildName.Text))
            {
                ShowValidation("請輸入兒童名字。", txtChildName);
                return false;
            }

            var birthDate = dtpBirthDate.Value.Date;
            var testDate = dtpTestDate.Value.Date;
            if (!TryValidateAge(birthDate, testDate, out var ageError))
            {
                ShowValidation(ageError, dtpTestDate);
                return false;
            }

            if (chkEnableReportPassword.Checked && string.IsNullOrWhiteSpace(txtPasswordInput.Text))
            {
                ShowValidation("請輸入報告密碼。", txtPasswordInput);
                return false;
            }

            return true;
        }

        private void ShowValidation(string message, Control control)
        {
            DevExpress.XtraEditors.XtraMessageBox.Show(
                TraditionalChineseHelper.Convert(message),
                TraditionalChineseHelper.Convert("提示"),
                MessageBoxButtons.OK,
                MessageBoxIcon.Information);
            control.Focus();
        }

        protected virtual bool TryValidateAge(DateTime birthDate, DateTime testDate, out string message)
        {
            if (testDate < birthDate)
            {
                message = "測試日期不可早於出生日期。";
                return false;
            }

            var ageInMonths = CalculateAgeInMonths(birthDate, testDate);
            if (ageInMonths > MaxMonthsForTypeA)
            {
                message = "該測試僅適用三歲以內的兒童，請調整出生日期或測試日期。";
                return false;
            }

            message = string.Empty;
            return true;
        }

        protected static int CalculateAgeInMonths(DateTime birthDate, DateTime testDate)
        {
            var months = (testDate.Year - birthDate.Year) * MonthsPerYear + (testDate.Month - birthDate.Month);
            if (testDate.Day < birthDate.Day)
            {
                months--;
            }

            return months;
        }

        private string GetSelectedGender() => radioGenderFemale.Checked ? "女性" : "男性";

        private string GetSelectedHandPreference()
        {
            if (radioHandLeft.Checked)
            {
                return "左手";
            }

            if (radioHandUnknown.Checked)
            {
                return "不确定";
            }

            return "右手";
        }

        private string GetSelectedReliability() => radioReliability90.Checked ? "90%" : "95%";

        private string GetSelectedSignificance()
        {
            if (radioSignificance005.Checked)
            {
                return "0.05";
            }

            if (radioSignificance010.Checked)
            {
                return "0.10";
            }

            if (radioSignificance015.Checked)
            {
                return "0.15";
            }

            return "0.01";
        }

        private string GetSelectedComparisonBasis() => "全样本";

        private string GetSelectedCalculationMethod() => radioMethodProportion.Checked ? "比例估算法" : "替代分检验";

        private string GetSelectedAlternativeMethod() => radioAlternativeProportion.Checked ? "比例估算法" : "替代分检验";

        private static string? GetComboSelectionValue(System.Windows.Forms.ComboBox comboBox)
        {
            return comboBox.SelectedIndex >= 0 ? comboBox.SelectedItem?.ToString() : null;
        }

        private static object ToDbValue(string? value)
        {
            return string.IsNullOrWhiteSpace(value) ? DBNull.Value : value.Trim();
        }

        private static void AddScoreParameter(MySqlCommand command, string name, NumericUpDown control)
        {
            var parameter = new MySqlParameter(name, MySqlDbType.Decimal)
            {
                Precision = 10,
                Scale = 2,
                Value = control.Value
            };
            command.Parameters.Add(parameter);
        }

        private static string ResolveUserAccount()
        {
            return string.IsNullOrWhiteSpace(SessionContext.UserAccount)
                ? Environment.UserName
                : SessionContext.UserAccount;
        }

        private void SaveEntry()
        {
            if (!ValidateInputs())
            {
                return;
            }

            try
            {
                using var connection = new MySqlConnection(DatabaseConfig.ConnectionString);
                using var command = new MySqlCommand("usp_SaveTestEntry", connection)
                {
                    CommandType = CommandType.StoredProcedure
                };

                command.Parameters.AddWithValue("@p_EntryID", (object?)entryId ?? DBNull.Value);
                command.Parameters.AddWithValue("@p_ParameterNumber", txtParameterCode.Text.Trim());
                command.Parameters.AddWithValue("@p_MainTesterName", txtTesterName.Text.Trim());
                command.Parameters.AddWithValue("@p_ChildName", txtChildName.Text.Trim());
                command.Parameters.AddWithValue("@p_TestDate", dtpTestDate.Value.Date);
                command.Parameters.AddWithValue("@p_BirthDate", dtpBirthDate.Value.Date);
                command.Parameters.AddWithValue("@p_Grade", ToDbValue(GetComboSelectionValue(cmbGrade)));
                command.Parameters.AddWithValue("@p_ParentEducation", ToDbValue(GetComboSelectionValue(cmbParentEducation)));
                command.Parameters.AddWithValue("@p_PhoneNumber", ToDbValue(txtPhoneNumber.Text));
                command.Parameters.AddWithValue("@p_VideoGame", ToDbValue(txtVideoGames.Text));
                command.Parameters.AddWithValue("@p_Address", ToDbValue(txtContactAddress.Text));
                command.Parameters.AddWithValue("@p_Remarks", ToDbValue(memoParentRemark.Text));
                command.Parameters.AddWithValue("@p_ChildGender", GetSelectedGender());
                command.Parameters.AddWithValue("@p_HandPreference", GetSelectedHandPreference());

                AddScoreParameter(command, "@p_Blocks", numBlock);
                AddScoreParameter(command, "@p_Comprehension", numInformation);
                AddScoreParameter(command, "@p_MatrixReasoning", numMatrix);
                AddScoreParameter(command, "@p_BugSearch", numBugSearch);
                AddScoreParameter(command, "@p_PictureMemory", numPictureMemory);
                AddScoreParameter(command, "@p_Similarities", numSimilarities);
                AddScoreParameter(command, "@p_PictureConcepts", numConcepts);
                AddScoreParameter(command, "@p_Cancellation", numCancellation);
                AddScoreParameter(command, "@p_AnimalHome", numAnimalHome);
                AddScoreParameter(command, "@p_Puzzle", numPuzzle);
                AddScoreParameter(command, "@p_AnimalCoding", numAnimalCoding);
                AddScoreParameter(command, "@p_Understanding", numComprehension);
                AddScoreParameter(command, "@p_PictureRecognition", numPictureRecognition);
                AddScoreParameter(command, "@p_PictureNaming", numPictureNaming);
                AddScoreParameter(command, "@p_RandomCancellation", numRandomCancellation);
                AddScoreParameter(command, "@p_OrderedCancellation", numOrderedCancellation);

                command.Parameters.AddWithValue("@p_ConfidenceLevel", GetSelectedReliability());
                command.Parameters.AddWithValue("@p_StatisticalSignificance", GetSelectedSignificance());
                command.Parameters.AddWithValue("@p_ComparisonBasis", GetSelectedComparisonBasis());
                command.Parameters.AddWithValue("@p_CalculationMethod", GetSelectedCalculationMethod());
                command.Parameters.AddWithValue("@p_CalculationMethod2", GetSelectedAlternativeMethod());
                command.Parameters.AddWithValue("@p_FilePath", ToDbValue(currentFilePath));
                string? encryptedPassword = null;
                if (chkEnableReportPassword.Checked)
                {
                    var plainPassword = txtPasswordInput.Text.Trim();
                    encryptedPassword = ReportPasswordProtector.Encrypt(plainPassword);
                }
                command.Parameters.AddWithValue("@p_ReportPassword", ToDbValue(encryptedPassword));
                command.Parameters.AddWithValue("@p_FType", fType.ToString());
                command.Parameters.AddWithValue("@p_UserAccount", ResolveUserAccount());

                var resultCodeParam = new MySqlParameter("@p_ResultCode", MySqlDbType.Int32)
                {
                    Direction = ParameterDirection.Output
                };
                var resultMessageParam = new MySqlParameter("@p_ResultMessage", MySqlDbType.VarChar, 200)
                {
                    Direction = ParameterDirection.Output
                };
                command.Parameters.Add(resultCodeParam);
                command.Parameters.Add(resultMessageParam);

                connection.Open();
                MySqlCollationHelper.EnsureGeneralCollation(connection);
                command.ExecuteNonQuery();

                var resultCode = resultCodeParam.Value != DBNull.Value ? Convert.ToInt32(resultCodeParam.Value) : 0;
                var resultMessage = resultMessageParam.Value?.ToString();

                if (resultCode != 0)
                {
                    var fallback = TraditionalChineseHelper.Convert("保存失敗，請稍後再試。");
                    var message = string.IsNullOrWhiteSpace(resultMessage)
                        ? fallback
                        : TraditionalChineseHelper.Convert(resultMessage);
                    DevExpress.XtraEditors.XtraMessageBox.Show(
                        message,
                        TraditionalChineseHelper.Convert("保存失敗"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                    return;
                }

                DialogResult = DialogResult.OK;
                Close();
            }
            catch (Exception ex)
            {
                DevExpress.XtraEditors.XtraMessageBox.Show(
                    TraditionalChineseHelper.Convert($"保存過程中出現錯誤：{ex.Message}"),
                    TraditionalChineseHelper.Convert("錯誤"),
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
		}

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            SaveEntry();
        }

        private bool IsDesignMode()
        {
            return LicenseManager.UsageMode == LicenseUsageMode.Designtime;
        }

        private void AttachDragHandler(Control control)
        {
            control.MouseDown += Control_MouseDown;
            control.MouseMove += Control_MouseMove;
            control.MouseUp += Control_MouseUp;
        }

        private void Control_MouseDown(object? sender, MouseEventArgs e)
        {
            if (sender is Control ctrl && e.Button == MouseButtons.Left)
            {
                isDragging = true;
                dragOffset = new Point(e.X, e.Y);
                ctrl.Capture = true;
            }
        }

        private void Control_MouseMove(object? sender, MouseEventArgs e)
        {
            if (isDragging && sender is Control ctrl)
            {
                var newLocation = ctrl.Location;
                newLocation.Offset(e.X - dragOffset.X, e.Y - dragOffset.Y);
                ctrl.Location = newLocation;
            }
        }

        private void Control_MouseUp(object? sender, MouseEventArgs e)
        {
            if (sender is Control ctrl)
            {
                isDragging = false;
                ctrl.Capture = false;
            }
        }
    }
}
